package com.cug;

import com.google.protobuf.InvalidProtocolBufferException;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSource;
import okio.ByteString;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

public class ClientReceiveProtobuf {

    private static final String API_URL = "http://114.55.113.162:6112/predict/process_json/";
//    private static final String API_URL = "http://127.0.0.1:6112/predict/process_json/";

    private static final String JSON_BODY = "{\n" +
            "  \"headers\": [\"TIME\", \"TA_SJA_09XGD_IN:SNQ\", \"TA_SJA_CHANGQING:SNQ\", \"TK_PYZGX_WEN23:SNQ\", \"TA_SJB_CHANGQING:SNQ\"],\n" +
            "  \"data\": [\n" +
            "    [\"\", \"2274\", \"2275\", \"2297\", \"2278\"],\n" +
            "    [\"2025/8/22 0:00\", \"36\", \"650\", \"120\", \"4750\"]\n" +
            "  ]\n" +
            "}";

    private static void parseProtobufStream(BufferedSource source) throws IOException {
        Buffer buffer = new Buffer();
        int messageCount = 0;
        long totalBytesReceived = 0;

        System.out.println("🔄 开始解析Protobuf流...");

        while (true) {
            long bytesRead = source.read(buffer, 8192);
            if (bytesRead == -1) break;

            totalBytesReceived += bytesRead;
//            System.out.println("📥 收到数据块: " + bytesRead + " bytes, 累计: " + totalBytesReceived + " bytes");

            while (buffer.size() >= 4) {
                try (BufferedSource peekSource = buffer.peek()) {
                    byte[] lengthBytes = peekSource.readByteArray(4);
                    int size = ByteBuffer.wrap(lengthBytes)
                            .order(ByteOrder.BIG_ENDIAN)
                            .getInt();

                    int totalMessageSize = 4 + size;
//                    System.out.println("📊 检测到消息: 长度字段=" + size + " bytes, 总大小=" + totalMessageSize + " bytes");

                    if (buffer.size() >= totalMessageSize) {
                        buffer.skip(4);
                        ByteString pbData = buffer.readByteString(size);

                        try {
                            Output.PredictionOutput msg = Output.PredictionOutput.parseFrom(pbData.toByteArray());
                            messageCount++;

                            // 详细打印每个消息的信息
                            printMessageDetails(messageCount, msg, pbData.size());

                        } catch (InvalidProtocolBufferException e) {
                            System.out.println("❌ 解析失败: " + e.getMessage());
                            System.out.println("     原始数据长度: " + pbData.size());
                            System.out.println("     错误位置: 消息#" + (messageCount + 1));
                        }
                    } else {
//                        System.out.println("⏳ 消息不完整，等待更多数据。当前buffer: " + buffer.size() + " bytes, 需要: " + totalMessageSize + " bytes");
                        break;
                    }
                }
            }
        }

        System.out.println("\n📋 解析完成统计:");
        System.out.println("✅ 成功解析消息数: " + messageCount);
        System.out.println("📦 总共接收字节数: " + totalBytesReceived + " bytes");

        if (messageCount == 0) {
            System.out.println("⚠️ 未收到任何有效消息，请检查服务端是否返回了正确格式的Protobuf流。");
        }
    }

    private static void printMessageDetails(int messageCount, Output.PredictionOutput msg, int pbSize) {
        // 使用固定长度的分隔线
        String doubleLine = "================================================================================";
        String singleLine = "--------------------------------------------------------------------------------";

        System.out.println("\n" + doubleLine);
        System.out.println("✅ 消息 " + messageCount);
        System.out.println(doubleLine);

        // 文件信息
        System.out.println("📄 文件名: " + (msg.getFilename().isEmpty() ? "未设置" : msg.getFilename()));
        System.out.println("🔢 Protobuf大小: " + pbSize + " bytes");
        System.out.println("📊 总字段数: " + msg.getSerializedSize() + " bytes");

        // 表头信息
        List<String> headers = msg.getHeadersList();
        System.out.println("🏷️  表头数量: " + headers.size());
//        System.out.println("   📋 表头内容: " + headers);

        // 数据信息
        List<Output.Row> dataList = msg.getDataList();
        System.out.println("📊 数据行数: " + dataList.size());

        if (!dataList.isEmpty()) {
            System.out.println("📄 数据详情（前3行）:");
            for (int i = 0; i < Math.min(dataList.size(), 3); i++) {
                Output.Row row = dataList.get(i);
//                System.out.println("   📝 第 " + (i + 1) + " 行: " + row.getValuesList());
                System.out.println("     列数: " + row.getValuesCount());
            }

            if (dataList.size() > 3) {
                System.out.println("   ... 还有 " + (dataList.size() - 3) + " 行数据");
            }
        } else {
            System.out.println("📭 无数据行");
        }

        // 消息摘要
        System.out.println("📈 消息摘要:");
        System.out.println("   - 总字符串字段数: " + countStringFields(msg));
        System.out.println("   - 预估总字符数: " + estimateTotalCharacters(msg));

        System.out.println(singleLine);
    }

    private static int countStringFields(Output.PredictionOutput msg) {
        int count = 0;
        if (!msg.getFilename().isEmpty()) count++;
        count += msg.getHeadersCount();
        for (Output.Row row : msg.getDataList()) {
            count += row.getValuesCount();
        }
        return count;
    }

    private static int estimateTotalCharacters(Output.PredictionOutput msg) {
        int totalChars = msg.getFilename().length();
        for (String header : msg.getHeadersList()) {
            totalChars += header.length();
        }
        for (Output.Row row : msg.getDataList()) {
            for (String value : row.getValuesList()) {
                totalChars += value.length();
            }
        }
        return totalChars;
    }

    public static void main(String[] args) {
        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
                .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                .build();

        RequestBody body = RequestBody.create(
                JSON_BODY,
                MediaType.get("application/json")
        );

        Request request = new Request.Builder()
                .url(API_URL)
                .post(body)
                .addHeader("Accept", "application/x-protobuf")
                .addHeader("Content-Type", "application/json")
                .build();

        long startTime = System.currentTimeMillis();
        System.out.println("🚀 开始请求: " + API_URL);
        System.out.println("📤 发送JSON: " + JSON_BODY.replace("\n", "").replace(" ", ""));

        try (Response response = client.newCall(request).execute()) {
            long responseTime = System.currentTimeMillis() - startTime;

            if (!response.isSuccessful()) {
                System.out.println("❌ 请求失败: " + response.code() + " " + response.body().string());
                return;
            }

            String contentType = response.header("Content-Type", "");
            System.out.println("📨 响应类型: " + contentType);
            System.out.println("⏱️  响应时间: " + responseTime + "ms");
            System.out.println("📦 响应大小: " + response.body().contentLength() + " bytes");

            if (!contentType.startsWith("application/x-protobuf")) {
                System.out.println("❌ 返回类型错误，期望 application/x-protobuf");
                String preview = response.body().string();
                System.out.println("💡 响应预览: " + (preview.length() > 300 ?
                        preview.substring(0, 300) + "..." : preview));
                return;
            }

            System.out.println("📥 开始接收Protobuf流...");

            try (BufferedSource source = response.body().source()) {
                parseProtobufStream(source);
            }

        } catch (IOException e) {
            long errorTime = System.currentTimeMillis() - startTime;
            System.out.println("❌ 请求异常，耗时: " + errorTime + "ms");

            String msg = e.getMessage();
            if (msg != null && (msg.contains("Connection") || msg.contains("connect"))) {
                System.out.println("❌ 无法连接到服务器，请确保FastAPI服务正在运行。");
            } else {
                System.out.println("❌ 发生错误: " + e.getMessage());
            }
            e.printStackTrace();
        }
    }
}